#include "game_logic.h"

//基础牌型判断

//检查清一色 
int logic_check_qing_yi_se(HoleMjs &holes, FormMjs &forms, OutMjs &outs) 
{
	std::vector<Mj> temp_mjs = holes.mjs;
	for (unsigned int i=0; i<forms.form_mjz.size(); i++)
	{
		Mj mj = forms.form_mjz[i].zu_mjs[0];
		temp_mjs.push_back(mj);
	}
	
	for (unsigned int i=0; i<temp_mjs.size(); i++)
	{
		if ( temp_mjs[i].color() != temp_mjs[0].color() ) //花色是否一样
		{
			return 0;
		}
	}
	return 1;
}

//检查七对
int logic_check_qidui(HoleMjs &holes, FormMjs &forms, OutMjs &outs)
{
	//最多14张牌
	int i_num = holes.mjs.size();
    if( i_num != 14 )
    {
		return 0;
    }
	//牌数应为3n+2
    if( i_num%3 != 2)
    {
		return 0;
    }

	//先装换成int型麻将数值数组
    int ia_mj[14];
    int i,j;
    for( i=0; i<i_num; i++ )
    {
        ia_mj[i] = holes.mjs[i].val;
    }
	
	//已经选择了的麻将
    int ia_selected[14] = {0};
    int i_sum=0;
    if( i_num == 14 )
	{	
		//看看是不是七对
        for(i=0; i<i_num; i++)
		{
            if( ia_selected[i] ) 
				continue;
			
            for( j=i+1; j<i_num; j++)
			{
                if( ia_selected[j] || j == i ) 
					continue;
                if( ia_mj[i] == ia_mj[j] )
				{
                    ia_selected[i] = ia_selected[j] = 1;
                    i_sum++;
                    break;
                }
            }
			
            if(ia_selected[i] == 0 ) 
				break;
         }
    }

	//至少是七对
    if( i_sum == 7 )
    {
    	//判断是否是豪华七对
		for (int i=0; i<i_num; i++)
		{			
			
			int count = 0;
			for (int j=0; j<i_num; j++)
			{
				if (  ia_mj[i] == ia_mj[j])
				{
					count ++;
				}
				if (count == 4 )
				{
					return 2;
				}
			}
		}
		//否则是普通七对
		return 1;
    }
	return 0;
}

//检查碰碰胡
int logic_check_pengpenghu(HoleMjs &holes, FormMjs &forms, OutMjs &outs)
{
	//最多14张牌
	int i_num = holes.mjs.size();
	//只剩两张牌，单吊，不算碰碰胡。
    if( i_num <=2  ||  i_num > 14 ||  i_num%3 != 2 )
    {
		return 0;
    }
	
	//先装换成int型麻将数值数组
    int ia_mj[14];
    int i;
    for( i=0; i<i_num; i++ )
    {
        ia_mj[i] = holes.mjs[i].val;
    }	
	//已经选择了的麻将
    int ia_selected[14] = {0};	
    return pengpenghu_base(ia_mj,i_num,ia_selected);
}

//检查单吊
int logic_check_dandiao(HoleMjs &holes, FormMjs &forms, OutMjs &outs)
{
	if (holes.mjs.size() != 2)
	{
		return 0;
	}
	if ( holes.mjs[0].val == holes.mjs[1].val)
	{
		return 1;
	}
	return 0;
}

//检查天胡
int logic_check_tianhu(HoleMjs &holes, FormMjs &forms, OutMjs &outs)
{

	

	return 0;
}


//胡牌_基础递归算法
bool hupai_base(int *pi_mj, int i_num, int *pi_select)
{    
	 //pi_select[]用于在递归调用时记录已经访问过的牌
     int i,j,k;
     int i_max,i_min,i_mid;
     int i_mark1,i_mark2;
     int i_have3=0;


     for(i=0; i<i_num; i++)
	 {
        if( pi_select[i] )
			continue;
        else
        {
			i_mark1 = i;
		}
		
        for( j=i+1; j<i_num; j++)
		{
            if( i == j )
				continue;
            if(pi_select[j]) 
				continue;
            else
            {
				i_mark2 = j;
            }

            for( k=j+1; k<i_num; k++)
			{
                if( i==k || j==k )
					continue;
                if( pi_select[k] )
					continue;
				
				/*说明可以找到3张未选择过的牌,
                 *如果最后i_have3 == 0,
                 *说明此时只有2张牌了.下面可以用i_mark1,i_mark2获得此二张. */
                i_have3 = 1;   

                i_max=0;
				i_min=100;
				
                i_max=std::max(pi_mj[i],std::max(pi_mj[j],pi_mj[k]));
                i_min=std::min(pi_mj[i],std::min(pi_mj[j],pi_mj[k]));
                i_mid=(i_max+i_min)/2;

                if( pi_mj[i] == pi_mj[j] 
					&& pi_mj[i] == pi_mj[k])  //表示能组成刻子
                {
                	//do nothing
                }
                else if( i_max-i_min == 2
						&& ( pi_mj[i]==i_mid || pi_mj[j] == i_mid || pi_mj[k] == i_mid)) //表示能组成顺子
                {
                	//do nothing
                }
                else
                    continue;

				//记录下来 下面递归
                pi_select[i] = pi_select[j] = pi_select[k] = 1; 

                if( !hupai_base(pi_mj, i_num, pi_select) ) 
				{
                    pi_select[i] = pi_select[j] = pi_select[k] = 0; //递归一次结束,返回
                     continue;
                }
				
				//选择的3张成刻、顺，而剩下的和了
                return true; 
            }
			
            //只剩两张牌, 相等
            if( (i_have3 == 0) && pi_mj[i_mark1] == pi_mj[i_mark2] )
            {
            	return true;
            }
        }
      }
	  //递归玩，不满足胡牌
      return false;
}



//碰碰胡_基础递归算法
int pengpenghu_base(int *pi_mj, int i_num, int *pi_select)
{    
	 //pi_select[]用于在递归调用时记录已经访问过的牌
     int i,j,k;
     int i_mark1,i_mark2;
     int i_have3=0;

     for(i=0; i<i_num; i++)
	 {
        if( pi_select[i] )
			continue;
        else
        {
			i_mark1 = i;
		}
		
        for( j=i+1; j<i_num; j++)
		{
            if( i == j )
				continue;
            if(pi_select[j]) 
				continue;
            else
            {
				i_mark2 = j;
            }

            for( k=j+1; k<i_num; k++)
			{
                if( i==k || j==k )
					continue;
                if( pi_select[k] )
					continue;
				
				/*说明可以找到3张未选择过的牌,
                 *如果最后i_have3 == 0,
                 *说明此时只有2张牌了.下面可以用i_mark1,i_mark2获得此二张. */
                i_have3 = 1;   
                if( pi_mj[i] == pi_mj[j] 
					&& pi_mj[i] == pi_mj[k])  //表示能组成刻子
                {
                	//do nothing
                }
                else
                    continue;

				//记录下来 下面递归
                pi_select[i] = pi_select[j] = pi_select[k] = 1; 

                if( !pengpenghu_base(pi_mj, i_num, pi_select) ) 
				{
                    pi_select[i] = pi_select[j] = pi_select[k] = 0; //递归一次结束,返回
                     continue;
                }
				
				//选择的3张成刻、顺，而剩下的和了
                return 1; 
            }
			
            //只剩两张牌, 相等
            if( (i_have3 == 0) && pi_mj[i_mark1] == pi_mj[i_mark2] )
            {
            	return 1;
            }
        }
      }
	  //递归完，不满足胡牌
      return 0;
}


bool seven_double_hupai(int * pi_mj, int i_num, int * pi_select)
{
	int i_sum(0);
	if (i_num == 14)
	{
		for (int i = 0; i < i_num; i++)
		{
			if (pi_select[i])
				continue;

			for (int j = i + 1; j < i_num; j++)
			{
				if (pi_select[j] || j == i)
					continue;
				if (pi_mj[i] == pi_mj[j])
				{
					pi_select[i] = pi_select[j] = 1;
					i_sum++;
					break;
				}
			}

			if (pi_select[i] == 0)
				break;
		}
		if (i_sum == 7)
		{
			return true;
		}
		for (int i = 0; i < i_num; i++)
		{
			pi_select[i] = 0;
		}
	}
	return false;
}

//3n+2 张牌能否胡牌
bool check_hupai(std::vector<Mj> mjs, int dq_val)
{
	if (dq_val == 1 || dq_val == 3 || dq_val == 5)
	{
		for (unsigned int i=0; i<mjs.size(); i++)
		{
			if (mjs[i].val / 10 == dq_val) 
			{
				return false;
			}
		}
	}
	//检查牌数量问题
	int i_num = mjs.size();
    if( i_num > 14 )
    {
		return false;
    }
    if( i_num%3 != 2)
    {
		return false;
    }
    int ia_mj[14];
    int i;
    for( i=0; i<i_num; i++ )
    {
        ia_mj[i] = mjs[i].val;
    }
	
    int ia_selected[14];
    for(i=0; i<i_num; i++) 
    {
		ia_selected[i] = 0;
    }
	//检查7小对
	if (seven_double_hupai(ia_mj, i_num, ia_selected))
	{
		return true;
	}
	
    return hupai_base(ia_mj,i_num,ia_selected);
}

bool get_tinghu_mjs(std::vector<Mj> v_mjs, std::vector<int> &v_ting, int dq_val)
{
	int ret = false;
	int count = v_mjs.size();
	if ( count%3 != 1 )
	{
		GAME_LOG.error("get_tinghu_mjs, v_mjs size error.\n");
		return ret;
	}
	
	for ( int mj_val=S1; mj_val<=S9; mj_val++ )
	{
		std::vector<Mj> mjs_temp = v_mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		
		if ( check_hupai(mjs_temp, dq_val))
		{
			ret = true;
			v_ting.push_back(mj_val);
		}
	}
	
	for ( int mj_val=T1; mj_val<=T9; mj_val++ )
	{
		std::vector<Mj> mjs_temp = v_mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		if ( check_hupai(mjs_temp, dq_val) )
		{
			ret = true;
			v_ting.push_back(mj_val);
		}
	}
	
	for (int mj_val =W1; mj_val<=W9; mj_val++)
	{
		std::vector<Mj> mjs_temp = v_mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		if ( check_hupai(mjs_temp, dq_val) )
		{
			ret = true;
			v_ting.push_back(mj_val);
		}
	}
	return ret;
}

bool check_ting(std::vector<Mj> v_mjs, int dq_val)
{
	int count = v_mjs.size();
	if (count%3 != 1)
	{
		GAME_LOG.error("check_ting, v_mjs size error.\n");
		return false;
	}
	
	for (int mj_val=S1; mj_val<=S9; mj_val++)
	{
		std::vector<Mj> mjs_temp = v_mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		if ( check_hupai(mjs_temp, dq_val) )
		{
			return true;
		}
	}
	
	for (int mj_val=T1; mj_val<=T9; mj_val++)
	{
		std::vector<Mj> mjs_temp = v_mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		if ( check_hupai(mjs_temp, dq_val) )
		{
			return true;
		}
	}
	
	for (int mj_val=W1; mj_val<=W9; mj_val++)
	{
		std::vector<Mj> mjs_temp = v_mjs;		
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		if ( check_hupai(mjs_temp, dq_val) )
		{
			return true;
		}
	}	
	return false;
}


bool check_baoting(std::vector<Mj> mjs, std::vector<int> &ting_out_mjval, int dq_val)
{
	int ret = false;
	unsigned int i_num = mjs.size();
	if ( i_num%3 != 2 )
	{
		GAME_LOG.error("check_tingpai, mjs size not 3n+2.\n");
		return ret;
	}
	//打出一张牌看能否听牌
	for (unsigned int i=0; i<i_num; i++)
	{
			Mj mj = mjs[i];
			std::vector<Mj> cp_mjs = mjs;
			
			//删除掉这个麻将
			std::vector<Mj>::iterator it;
			for (it=cp_mjs.begin(); it != cp_mjs.end(); )
			{
				if ((*it).val == mj.val)
				{
					cp_mjs.erase(it);
					break;
				}
				else
				{
					it++;
				}				
			}
			Mj::sort_by_ascending(cp_mjs);
			//Mj::dump_mjs(cp_mjs,"del_mjs");

			if ( check_ting(cp_mjs, dq_val))
			{			
				ting_out_mjval.push_back(mj.val);
				ret = true;	
			}		
	}
	return ret;
}

int remove_n_mj(std::vector<Mj> &mjs, Mj &mj, int cnt)
{
	std::vector<Mj>::iterator it;
	int c=0;
	for (it=mjs.begin(); it != mjs.end(); )
	{
		if ((*it).val == mj.val)
		{
			it = mjs.erase(it);
			c++;
			if (c == cnt)
			{
				break;
			}
		}
		else
		{
			it++;
		}
	}
	Mj::sort_by_ascending(mjs);
	return 0;
}

int get_one_mj_num(std::vector<Mj> &mjs, Mj mj)
{
	int cnt = 0;
	for (unsigned int i=0; i<mjs.size(); i++) 
	{
		if ( mjs[i].val == mj.val )
		{
			cnt++;
		}		
	}
	return cnt;
}



